<!DOCTYPE html>
<html>

<head>
  <title>Quarkus - Using HashiCorp Vault&#8217;s Transit Secret Engine</title>
  <script id="adobe_dtm" src="https://www.redhat.com/dtm.js" type="text/javascript"></script>
  <script src="/assets/javascript/highlight.pack.js" type="text/javascript"></script>
  <META HTTP-EQUIV='Content-Security-Policy' CONTENT="default-src 'none'; script-src 'self' 'unsafe-eval' 'sha256-ANpuoVzuSex6VhqpYgsG25OHWVA1I+F6aGU04LoI+5s=' 'sha256-ipy9P/3rZZW06mTLAR0EnXvxSNcnfSDPLDuh3kzbB1w=' js.bizographics.com https://www.redhat.com assets.adobedtm.com jsonip.com https://ajax.googleapis.com https://www.googletagmanager.com https://www.google-analytics.com https://use.fontawesome.com; style-src 'self' https://fonts.googleapis.com https://use.fontawesome.com; img-src 'self' *; media-src 'self' ; frame-src https://www.googletagmanager.com https://www.youtube.com; frame-ancestors 'none'; base-uri 'none'; object-src 'none'; form-action 'none'; font-src 'self' https://use.fontawesome.com https://fonts.gstatic.com;">
  <META HTTP-EQUIV='X-Frame-Options' CONTENT="DENY">
  <META HTTP-EQUIV='X-XSS-Protection' CONTENT="1; mode=block">
  <META HTTP-EQUIV='X-Content-Type-Options' CONTENT="nosniff">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Quarkus: Supersonic Subatomic Java">
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="@QuarkusIO"> 
  <meta name="twitter:creator" content="@QuarkusIO">
  <meta property="og:url" content="https://quarkus.io/guides/vault-transit" />
  <meta property="og:title" content="Quarkus - Using HashiCorp Vault&#8217;s Transit Secret Engine" />
  <meta property="og:description" content="Quarkus: Supersonic Subatomic Java" />
  <meta property="og:image" content="/assets/images/quarkus_card.png" />
  <link rel="canonical" href="https://quarkus.io/guides/vault-transit">
  <link rel="shortcut icon" type="image/png" href="/favicon.ico" >
  <link rel="stylesheet" href="https://quarkus.io/guides/stylesheet/config.css" />
  <link rel="stylesheet" href="/assets/css/main.css" />
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
  <link rel="alternate" type="application/rss+xml"  href="https://quarkus.io/feed.xml" title="Quarkus">
  <script src="https://quarkus.io/assets/javascript/goan.js" type="text/javascript"></script>
  <script src="https://quarkus.io/assets/javascript/hl.js" type="text/javascript"></script>
</head>

<body class="guides">
  <!-- Google Tag Manager (noscript) -->
  <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NJWS5L"
  height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
  <!-- End Google Tag Manager (noscript) -->

  <div class="nav-wrapper">
  <div class="grid-wrapper">
    <div class="width-12-12">
      <input type="checkbox" id="checkbox" />
      <nav id="main-nav" class="main-nav">
  <div class="container">
    <div class="logo-wrapper">
      
        <a href="/"><img src="/assets/images/quarkus_logo_horizontal_rgb_600px_reverse.png" class="project-logo" title="Quarkus"></a>
      
    </div>
    <label class="nav-toggle" for="checkbox">
      <i class="fa fa-bars"></i>
    </label>
    <div id="menu" class="menu">
      <span>
        <a href="/get-started/" class="">Get Started</a>
      </span>
      <span>
        <a href="/guides/" class="active">Guides</a>
      </span>
      <span>
        <a href="/community/" class="">Community</a>
      </span>
      <span>
        <a href="/support/" class="">Support</a>
      </span>
      <span>
        <a href="/blog/" class="">Blog</a>
      </span>
      <span>
        <a href="https://code.quarkus.io" class="button-cta secondary white">Start Coding</a>
      </span>
    </div>
  </div>
      </nav>
    </div>
  </div>
</div>

  <div class="content">
    <div class="guide">
  <div class="width-12-12">
    <h1 class="text-caps">Quarkus - Using HashiCorp Vault&#8217;s Transit Secret Engine</h1>
    <div class="hide-mobile toc"><ul class="sectlevel1">
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#setup">Setup</a></li>
<li><a href="#encrypt-and-decrypt">Encrypt and Decrypt</a></li>
<li><a href="#sign-and-verify">Sign and Verify</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul></div>
    <div>
      <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Vault&#8217;s Transit Secret Engine offers an "encryption as a service" functionality. It allows to store encryption
keys into Vault, and provides services to encrypt/decrypt and sign/verify arbitrary pieces of data. This brings
several advantages, such as:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>limited key exposure: keys never leave the Vault. Instead the data is sent to Vault to get
encrypted/decrypted/signed/verified.</p>
</li>
<li>
<p>reliable and consistent algorithms: algorithms are implemented by Vault. It supports a wide variety, and there is
only one implementation used for a given algorithm type, regardless of the client&#8217;s technology.</p>
</li>
<li>
<p>it relieves developers from having to embed cryptographic libraries into their applications.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In the context of Quarkus, the main (non administration) services are being covered:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>encrypt: encrypt some data and return the cipher text</p>
</li>
<li>
<p>decrypt: decrypt the cipher text and return the clear data</p>
</li>
<li>
<p>rewrap: reencrypt a cipher text using the most recent key version</p>
</li>
<li>
<p>sign: sign a piece of data</p>
</li>
<li>
<p>verify signature: verify that a signature is correct for a piece of data</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>See <a href="https://www.vaultproject.io/docs/secrets/transit/index.html#transit-secrets-engine">Vault Transit Secret Engine&#8217;s official documentation</a></p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This technology is considered preview.</p>
</div>
<div class="paragraph">
<p>In <em>preview</em>, backward compatibility and presence in the ecosystem is not guaranteed.
Specific improvements might require to change configuration or APIs and plans to become <em>stable</em> are under way.
Feedback is welcome on our <a href="https://groups.google.com/d/forum/quarkus-dev">mailing list</a> or as issues in our <a href="https://github.com/quarkusio/quarkus/issues">GitHub issue tracker</a>.</p>
</div>
<div class="paragraph">
<p>For a full list of possible extension statuses, check our <a href="https://quarkus.io/faq/#extension-status">FAQ entry</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="prerequisites"><a class="anchor" href="#prerequisites"></a>Prerequisites</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To complete this guide, you need:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>to complete the "Starting Vault" section of the <a href="vault">Vault guide</a></p>
</li>
<li>
<p>roughly 15 minutes</p>
</li>
<li>
<p>an IDE</p>
</li>
<li>
<p>JDK 1.8+ installed with <code>JAVA_HOME</code> configured appropriately</p>
</li>
<li>
<p>Apache Maven 3.6.2+</p>
</li>
<li>
<p>Docker installed</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="setup"><a class="anchor" href="#setup"></a>Setup</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We assume there is a Vault running from the <a href="vault">Vault guide</a>, and the root token is known.
The first step consists in activating the Transit Secret Engine, and creating the different keys:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">docker exec -it dev-vault sh
export VAULT_TOKEN=s.5VUS8pte13RqekCB2fmMT3u2

vault secrets enable transit
# ==&gt; Success! Enabled the transit secrets engine at: transit/

vault write -f transit/keys/my-encryption-key
# ==&gt; Success! Data written to: transit/keys/my-encryption-key

vault write transit/keys/my-sign-key type=ecdsa-p256
# ==&gt; Success! Data written to: transit/keys/my-sign-key</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that you did not have to provide the key value. You only provide its name, and Vault will generate it for you and
keep it secured.</p>
</div>
<div class="paragraph">
<p>Once the keys have been created, we now need to create a policy that provides access for it:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">cat &lt;&lt;EOF | vault policy write vault-transit-quickstart-policy -
path "transit/encrypt/my-encryption-key" {
  capabilities = [ "update" ]
}
path "transit/decrypt/my-encryption-key" {
  capabilities = [ "update" ]
}
path "transit/sign/my-sign-key" {
  capabilities = [ "update"]
}
path "transit/verify/my-sign-key" {
  capabilities = [ "update" ]
}
EOF
# ==&gt; Success! Uploaded policy: vault-transit-quickstart-policy</code></pre>
</div>
</div>
<div class="paragraph">
<p>And finally, let&#8217;s add the <code>vault-transit-quickstart-policy</code> to user <code>bob</code> that was created in the <a href="vault">Vault guide</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">vault write auth/userpass/users/bob password=sinclair policies=vault-quickstart-policy,vault-transit-quickstart-policy</code></pre>
</div>
</div>
<div class="paragraph">
<p>To check that the configuration is correct, try logging in:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">vault login -method=userpass username=bob password=sinclair</code></pre>
</div>
</div>
<div class="paragraph">
<p>You should see:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                    Value
---                    -----
token                  s.s93BVzJPzBiIGuYJHBTkG8Uw
token_accessor         OKNipTAgxWbxsrjixASNiwdY
token_duration         768h
token_renewable        true
token_policies         ["default" "vault-quickstart-policy"]
identity_policies      []
policies               ["default" "vault-quickstart-policy"]
token_meta_username    bob</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now set <code>VAULT_TOKEN</code> to the <code>token</code> above (instead of the root token), and try encrypting some data:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">export VAULT_TOKEN=s.s93BVzJPzBiIGuYJHBTkG8Uw
# note: "my secret data" in base64 is "bXkgc2VjcmV0IGRhdGEK"
vault write transit/encrypt/my-encryption-key plaintext=bXkgc2VjcmV0IGRhdGEK</code></pre>
</div>
</div>
<div class="paragraph">
<p>You should see:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">Key           Value
---           -----
ciphertext    vault:v1:vIQxsLANFbcfKofJL55zjoIXV6MqAzvjKUUQLGg5pWTz0W2Qab/B4nEJaQ==</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="encrypt-and-decrypt"><a class="anchor" href="#encrypt-and-decrypt"></a>Encrypt and Decrypt</h2>
<div class="sectionbody">
<div class="paragraph">
<p>First, let&#8217;s create a simple Quarkus application with vault and jsonb capabilities:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">mvn io.quarkus:quarkus-maven-plugin:1.7.0.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=vault-transit-quickstart \
    -DclassName="org.acme.quickstart.GreetingResource" \
    -Dpath="/hello" \
    -Dextensions="vault,resteasy-jsonb"
cd vault-transit-quickstart</code></pre>
</div>
</div>
<div class="paragraph">
<p>Now, configure access to Vault from the <code>application.properties</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="properties" class="language-properties hljs"># vault url
quarkus.vault.url=http://localhost:8200

# vault authentication
quarkus.vault.authentication.userpass.username=bob
quarkus.vault.authentication.userpass.password=sinclair</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that you did not need to specify the existence of a particular encryption key in the configuration. You only
do so in special cases such as specifying the key type for upsert, or changing the signature algorithm, &#8230;&#8203; Check the complete configuration for more
information.</p>
</div>
<div class="paragraph">
<p>We can then add a new endpoint that will allow us to encrypt and decrypt data:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">@Path("/transit")
@Produces(TEXT_PLAIN)
@Consumes(TEXT_PLAIN)
public class TransitResource {

    @Inject
    public VaultTransitSecretEngine transitSecretEngine;

    @POST
    @Path("/encrypt")
    public String encrypt(String clearData) {
        return transitSecretEngine.encrypt("my-encryption-key", clearData);
    }

    @POST
    @Path("/decrypt")
    public String decrypt(String cipherText) {
        return transitSecretEngine.decrypt("my-encryption-key", cipherText).asString();
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>After compiling and starting the Quarkus application, let&#8217;s encrypt some data:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">curl -X POST --data 'some secret data' --header "Content-Type: text/plain"  http://localhost:8080/transit/encrypt
# ==&gt; vault:v1:fN4P7WNjIegpb3lD/pSuhXvyONhGrI21gcKNcedk+5jpjguOw6JkqXYXlkY=</code></pre>
</div>
</div>
<div class="paragraph">
<p>And decrypt back this cipher text:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">curl -X POST --data 'vault:v1:fN4P7WNjIegpb3lD/pSuhXvyONhGrI21gcKNcedk+5jpjguOw6JkqXYXlkY=' --header "Content-Type: text/plain"  http://localhost:8080/transit/decrypt
# ==&gt; some secret data</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="sign-and-verify"><a class="anchor" href="#sign-and-verify"></a>Sign and Verify</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Let&#8217;s add 2 new methods to our <code>TransitResource</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">@POST
@Path("/sign")
public String sign(String input) {
    return transitSecretEngine.sign("my-sign-key", input);
}

public static class VerifyRequest {
    public String signature;
    public String input;
}

@POST
@Path("/verify")
@Consumes(APPLICATION_JSON)
public Response verify(VerifyRequest request) {
    transitSecretEngine.verifySignature("my-sign-key", request.signature, request.input);
    return Response.accepted().build();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>And start signing some data:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">curl -X POST --data 'some secret data' --header "Content-Type: text/plain"  http://localhost:8080/transit/sign
# ==&gt; vault:v1:MEUCIQDl+nE4y4E878bkugGG6FG1/RsttaQnoWfZHppeuk4TnQIgTGWTtMhVPCzN8VH/EEr2qp5h34lI1bnEP6L1F+QQoPI=</code></pre>
</div>
</div>
<div class="paragraph">
<p>And finally, let&#8217;s make sure the signature is matching our input data:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="shell" class="language-shell hljs">curl -v -X POST --data '{"input":"some secret data","signature":"vault:v1:MEUCIQDl+nE4y4E878bkugGG6FG1/RsttaQnoWfZHppeuk4TnQIgTGWTtMhVPCzN8VH/EEr2qp5h34lI1bnEP6L1F+QQoPI="}' --header "Content-Type: application/json" http://localhost:8080/transit/verify
# ==&gt; ... &lt; HTTP/1.1 202 Accepted</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="conclusion"><a class="anchor" href="#conclusion"></a>Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The Transit Secret Engine is a powerful tool in the enterprise.
We have seen the most obvious functions of the interface, but the rest of the methods or flavors
should not be overlooked:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>For instance batch oriented methods are strongly recommended for mass operations (encrypt, decrypt, &#8230;&#8203;)</p>
</li>
<li>
<p>Transit contexts allow key derivation where one key is used to derive other keys for specific named contexts
(e.g. person names, person addresses, &#8230;&#8203;)</p>
</li>
<li>
<p>Rewrapping allows to reencrypt data with the most recent key version when the Vault administrator decides to
rotate keys</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Feel free to look at the <code>VaultTransitSecretEngine</code> interface plus the dedicated Transit Secret Engine configuration
properties in the <a href="vault">Vault guide</a> for all the details.</p>
</div>
</div>
</div>
    </div>
  </div>
</div>

  </div>

  <div class="content project-footer">
  <div class="footer-section">
    <div class="logo-wrapper">
      <a href="/"><img src="/assets/images/quarkus_logo_horizontal_rgb_reverse.svg" class="project-logo" title="Quarkus"></a>
    </div>
  </div>
  <div class="grid-wrapper">
    <p class="grid__item width-3-12">Quarkus is open. All dependencies of this project are available under the <a href='https://www.apache.org/licenses/LICENSE-2.0' target='_blank'>Apache Software License 2.0</a> or compatible license.<br /><br />This website was built with <a href='https://jekyllrb.com/' target='_blank'>Jekyll</a>, is hosted on <a href='https://pages.github.com/' target='_blank'>Github Pages</a> and is completely open source. If you want to make it better, <a href='https://github.com/quarkusio/quarkusio.github.io' target='_blank'>fork the website</a> and show us what you’ve got.</p>

    
      <div class="width-1-12 project-links">
        <span>Navigation</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="/">Home</a></li>
          
            <li><a href="/guides">Guides</a></li>
          
            <li><a href="/community/#contributing">Contribute</a></li>
          
            <li><a href="/faq">FAQ</a></li>
          
            <li><a href="/get-started">Get Started</a></li>
          
        </ul>
      </div>
    
      <div class="width-1-12 project-links">
        <span>Contribute</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="https://twitter.com/quarkusio">Follow us</a></li>
          
            <li><a href="https://github.com/quarkusio">GitHub</a></li>
          
            <li><a href="/security">Security&nbsp;policy</a></li>
          
        </ul>
      </div>
    
      <div class="width-1-12 project-links">
        <span>Get Help</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="https://groups.google.com/forum/#!forum/quarkus-dev">Forums</a></li>
          
            <li><a href="https://quarkusio.zulipchat.com">Chatroom</a></li>
          
        </ul>
      </div>
    

    
      <div class="width-3-12 more-links">
        <span>Quarkus is made of community projects</span>
        <ul class="footer-links">
          
            <li><a href="https://vertx.io/" target="_blank">Eclipse Vert.x</a></li>
          
            <li><a href="https://microprofile.io" target="_blank">Eclipse MicroProfile</a></li>
          
            <li><a href="https://hibernate.org" target="_blank">Hibernate</a></li>
          
            <li><a href="https://netty.io" target="_blank">Netty</a></li>
          
            <li><a href="https://resteasy.github.io" target="_blank">RESTEasy</a></li>
          
            <li><a href="https://camel.apache.org" target="_blank">Apache Camel</a></li>
          
            <li><a href="https://code.quarkus.io/" target="_blank">And many more...</a></li>
          
        </ul>
      </div>
    
  </div>
</div>
  <div class="content redhat-footer">
  <div class="grid-wrapper">
    <span class="licence">
      <i class="fab fa-creative-commons"></i><i class="fab fa-creative-commons-by"></i> <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank">CC by 3.0</a> | <a href="https://www.redhat.com/en/about/privacy-policy">Privacy Policy</a>
    </span>
    <span class="redhat">
      Sponsored by
    </span>
    <span class="redhat-logo">
      <a href="https://www.redhat.com/" target="_blank"><img src="/assets/images/redhat_reversed.svg"></a>
    </span>
  </div>
</div>


  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" integrity="sha384-8gBf6Y4YYq7Jx97PIqmTwLPin4hxIzQw5aDmUg/DDhul9fFpbbLcLh3nTIIDJKhx" crossorigin="anonymous"></script>
  <script type="text/javascript" src="/assets/javascript/mobile-nav.js"></script>
  <script type="text/javascript" src="/assets/javascript/scroll-down.js"></script>
  <script src="/assets/javascript/satellite.js" type="text/javascript"></script>
  <script src="https://quarkus.io/guides/javascript/config.js" type="text/javascript"></script>
  <script src="/assets/javascript/search-filter.js" type="text/javascript"></script>
  <script src="/assets/javascript/back-to-top.js" type="text/javascript"></script>
</body>

</html>
